package com.youedata.solr;
import com.youedata.util.Page;
import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.AnalysisParams;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 * Created by gaodao on 16/9/9.
 */
public class SolrUtil {

    static Logger logger = Logger.getLogger(SolrUtil.class);

    public static String SEARCH_CONDITION_RELATION_AND = " AND ";
    public static String SEARCH_CONDITION_RELATION_OR = " OR ";

    public static String SEARCH_CONDITION_DEFAULT_ALL = "*:*";
    public static String SEARCH_CONDITION_DEFAULT_NULL = "";

    /**
     * 添加，修改索引
     * 根据map建立索引或修改索引，map中的key:字段名称 value:该字段对应的值
     * @return 成功true,失败false
     * 无需在代码中对某字段设置是否分词，只要在scheme.xml文件设置就行。
     */
    public static boolean addIndexByMap(Map<String,Object> map,SolrClient solrClient){
        boolean flag = false;
        SolrInputDocument document = new SolrInputDocument();
        try {
            String temp = null;
            for(Map.Entry<String, Object> entry : map.entrySet()){
                String fieldName = entry.getKey();
                Object fieldValue = entry.getValue();
                document.addField(fieldName, fieldValue);
            }
            solrClient.add(document);
            solrClient.commit();
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }



    /**
     * 将整个对象都添加到索引
     * @author wuyw
     * @param <T>
     * @date 2015-8-30 下午5:35:34
     */
    public static <T> void addBean(T obj, SolrClient solrClient) {
        try {
            solrClient.addBean(obj);
            solrClient.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加多个索引对象
     *
     * @param <T>
     * @date 2015-8-30 下午5:36:37
     */
    public static <T> void addBeans(List<T> list, SolrClient solrClient) {
        try {
            solrClient.addBeans(list);
            solrClient.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据id删除某条索引
     *
     * @date 2015-8-30 下午5:37:46
     * @param id
     */
    public static void deleteById(String id, SolrClient solrClient) {
        try {
            solrClient.deleteById(id);
            solrClient.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据查询语句删除索引
     *
     * @date 2015-8-30 下午5:38:46
     * @param query
     */
    public static void deleteByQuery(String query, SolrClient solrClient) {
        try {
            solrClient.deleteByQuery(query);
            solrClient.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void deleteAll(SolrClient solrClient) {
        try {
            String query = "*:*";
            solrClient.deleteByQuery(query);
            solrClient.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static <T> T solrDocToBean(SolrDocument sd,Class<T> clazz){
        // 获取javaBean属性
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(clazz);
            // 创建 JavaBean 对象
            Object obj = clazz.newInstance();
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            if (propertyDescriptors != null && propertyDescriptors.length > 0) {
                String propertyName = null; // javaBean属性名
                Object propertyValue = null; // javaBean属性值
                for (PropertyDescriptor pd : propertyDescriptors) {
                    propertyName = pd.getName();
                    if(pd.getName().equals("class")){
                        continue;
                    }
                    try{
                        //先从keyMap中取出javaBean属性对应mysql字段值
                        //将上一步中取出的mysql字段名称作为key,从sqlResultMap中取出值,然后赋值给javaBean
                        propertyValue = sd.getFieldValue(propertyName);
                        //处理int,long ,double,short,float,byte,boolean 等空值情况,这些类型值不能为null否则会报错
                        if(propertyValue == null){
                            if(pd.getPropertyType() == int.class || pd.getPropertyType() == long.class || pd.getPropertyType() == double.class || pd.getPropertyType() == float.class || pd.getPropertyType() == byte.class ){
                                propertyValue = 0;
                            } else if(pd.getPropertyType() == boolean.class){
                                propertyValue = false;
                            } else if(pd.getPropertyType() ==short.class){
                                propertyValue = (short) 0;
                            }else if(pd.getPropertyType() == byte.class){
                                propertyValue = (byte) 0;
                            }
                        }else if((propertyValue instanceof BigDecimal) && (pd.getPropertyType() == double.class || pd.getPropertyType() == Double.class)){
                            //对于mysql返回的bigDecimal类型转成bean中定义的double类型
                            propertyValue = ((BigDecimal) propertyValue).doubleValue();
                        }else if((propertyValue instanceof BigDecimal) && (pd.getPropertyType() == float.class || pd.getPropertyType() == Float.class)){
                            //对于mysql返回的bigDecimal类型转成bean中定义的float类型
                            propertyValue = ((BigDecimal) propertyValue).floatValue();

                        }else if(pd.getPropertyType() == short.class){
                            propertyValue = Short.valueOf(String.valueOf(propertyValue));
                        }else if(pd.getPropertyType() == byte.class){
                            propertyValue = Byte.parseByte(String.valueOf(propertyValue));
                        }
                        pd.getWriteMethod().invoke(obj, new Object[] { propertyValue });
                    }catch (Exception e){
                        logger.info("mysqlMap2bean处理字段错误:"+ propertyName+" errmsg:"+e.getMessage());
                        e.printStackTrace();
                    }

                }
                return (T) obj;
            }
        }catch(Exception e){
            e.printStackTrace();;
            logger.error("solrDoc转bean失败  errmsg:"+e.getMessage());
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    public static <T> T queryById(String id, Class<T> entityClass, SolrClient solrClient) {
        SolrQuery query = new SolrQuery();
        query.setQuery("id:" + id);
        QueryResponse response = null;
        try {
            response = solrClient.query(query);
        } catch (Exception e) {
            e.printStackTrace();
        }
        SolrDocumentList docs = response.getResults();
        if(null == docs || docs.size() == 0) {
            return null;
        }
        SolrDocument doc = docs.get(0);
        return solrDocToBean(doc,entityClass);
    }

    /**
     * solr获取的分页对象
     *
     * @param <T>
     * @date 2015-8-30 下午5:39:36
     * @param page
     * @param solrQuery 里面封装了查询对象的条件
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> Page getBeanPage(Page<T> page, SolrQuery solrQuery, SolrClient solrClient, Class<T> entityClass) {
        solrQuery.setStart(page.getStart());//开始索引
        solrQuery.setRows(page.getPageSize());//分页的数量
        QueryResponse queryResponse = null;
        try {
            logger.debug("solrQuery:"+solrQuery);
            queryResponse = solrClient.query(solrQuery);

        } catch (Exception e) {
            e.printStackTrace();
        }
        SolrDocumentList docs = queryResponse.getResults();
        List<T> list = new ArrayList<T>(0);
        if(docs!=null && !docs.isEmpty()){
            for(SolrDocument doc : docs){
                //logger.info("doc:"+ JSON.toJSONString(doc));
                T obj = solrDocToBean(doc,entityClass);
                list.add(obj);
            }
        }
        page.setTotalRow((int)docs.getNumFound());
        page.setDataList(list);
        return page;
    }


    /**
     * 只查询id集合
     * @param solrQuery
     * @param solrClient
     * @param length
     * @return
     */
    public static List<Long> getIdList(SolrQuery solrQuery, SolrClient solrClient,int length) {
        String idFieldName = "id";
        solrQuery.setFields(idFieldName);
        solrQuery.setStart(0);//开始索引
        solrQuery.setRows(length);//分页的数量
        QueryResponse queryResponse = null;
        try {
            logger.debug("solrQuery:"+solrQuery);
            queryResponse = solrClient.query(solrQuery);

        } catch (Exception e) {
            e.printStackTrace();
        }
        SolrDocumentList docs = queryResponse.getResults();
        List<Long> idList = new ArrayList<>();
        if(docs!=null && !docs.isEmpty()){
            for(SolrDocument doc : docs){
                Object obj = doc.getFieldValue(idFieldName);
                if(obj != null){
                    idList.add((long)obj);
                }
            }
        }
        return idList;
    }

    /**
     * 查询后按照需要的返回结构类型返回Map对象集合
     * @param page
     * @param solrQuery   查询条件
     * @param returnMapKeyArray  返回key值数组
     * @param solrClient
     * @return
     */
    public static Page getMapPage(Page page, SolrQuery solrQuery,String[] returnMapKeyArray, SolrClient solrClient) {

        solrQuery.setStart(page.getStart());//开始索引
        solrQuery.setRows(page.getPageSize());//分页的数量
        logger.debug("solrQuery:"+solrQuery.toString());
        logger.debug("solrQuery:"+solrQuery.getQuery());
        QueryResponse queryResponse = null;
        try {
            queryResponse = solrClient.query(solrQuery, SolrRequest.METHOD.POST);
        } catch (Exception e) {
            e.printStackTrace();
        }
        SolrDocumentList docs = queryResponse.getResults();
        List<Map> resultList = new ArrayList<Map>();
        if(docs!=null && !docs.isEmpty()){
            for(SolrDocument doc : docs){
                Map<String,Object> map = new HashMap<String,Object>();
                for(String key:returnMapKeyArray){
                    map.put(key,doc.getFieldValue(key));
                }
                resultList.add(map);
            }
        }
        page.setTotalRow((int)docs.getNumFound());
        page.setDataList(resultList);
        return page;
    }

    /**
     * 优化solr索引
     *
     * @date 2015-8-31 上午12:02:49
     * @param solrClient
     */
    public static void optimize(String collection, SolrClient solrClient) {
        try {
            solrClient.optimize(collection);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 优化solr索引
     *
     * @date 2015-8-31 上午12:02:49
     * @param solrClient
     */
    public static void optimize(SolrClient solrClient) {
        try {
            solrClient.optimize();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("unchecked")
    /**
     * 重新将需要查询的文本内容解析成分词
     * @param core
     * @param searchText
     * @return
     * @throws SolrServerException
     */
    public static String analysisSearchText(SolrClient solrClient, String searchText) {
        try{
            StringBuilder strSearchText = new StringBuilder();
            final String STR_FIELD_TYPE = "text_mmseg4j_simple";
            SolrQuery queryAnalysis = new SolrQuery();
            queryAnalysis.add(CommonParams.QT, "/analysis/field"); // query type
            queryAnalysis.add(AnalysisParams.FIELD_VALUE, searchText);
            queryAnalysis.add(AnalysisParams.FIELD_TYPE, STR_FIELD_TYPE);
            QueryResponse responseAnalysis = solrClient.query(queryAnalysis);
            //对响应进行解析
            NamedList<Object> analysis = (NamedList<Object>) responseAnalysis.getResponse().get("analysis");// analysis node
            NamedList<Object> field_types = (NamedList<Object>) analysis.get("field_types");// field_types node
            NamedList<Object> fieldType = (NamedList<Object>) field_types.get(STR_FIELD_TYPE);// text_cn node
            NamedList<Object> index = (NamedList<Object>) fieldType.get("index");// index node
            List<SimpleOrderedMap<String>> list = (ArrayList<SimpleOrderedMap<String>>)index.get("com.chenlb.mmseg4j.analysis.MMSegTokenizer");// tokenizer node
            // 在每个词条中间加上空格，为每个词条进行或运算
            for(Iterator<SimpleOrderedMap<String>> iter = list.iterator(); iter.hasNext();)
            {
                strSearchText.append(iter.next().get("text") + " ");
            }
            return strSearchText.toString();
        }catch (SolrServerException e){
            e.printStackTrace();
            logger.error("分析转换solr查询条件出错 SolrServerException");
        }catch(IOException e){
            e.printStackTrace();
            logger.error("分析转换solr查询条件出错 IOException");
        }
        return searchText;

    }

    /**
     * 获取solr查询条件
     * @param conditionMap
     * @param conditionRelation
     * @param defaultVlue 没有得到查询条件时，返回的默认查询条件
     * @return
     */
    public static String getQueryByMap(Map<String,Object> conditionMap,String conditionRelation,String defaultVlue){
        if(conditionMap!=null && !conditionMap.isEmpty()){
            StringBuilder res = new StringBuilder();
            Iterator it = conditionMap.keySet().iterator();
            int i = 0;
            while (it.hasNext()){
                if(i>0){
                    res.append(conditionRelation);
                }
                String key = (String)it.next();
                res.append(key).append(":").append(conditionMap.get(key));
                i++;
            }
            return res.toString();
        }
        return defaultVlue;
    }

    /**
     * 获取多值查询条件值
     * @param valueArray
     * @return
     */
    public static String getConditionValueForArrayValue(String[] valueArray){
        if(valueArray!=null && valueArray.length>0){
            StringBuilder fvalue = new StringBuilder();
            fvalue.append(" ( ");
            for(int i=0;i<valueArray.length;i++){
                if(i>0){
                    fvalue.append(" OR ");
                }
                fvalue.append(valueArray[i]);
            }
            fvalue.append(" )");
            return fvalue.toString();
        }
        return "*";
    }
    /**
     * 获取多值查询条件值
     * @param valueList
     * @return
     */
    public static String getConditionValueForArrayValue(List<String> valueList){
        if(valueList!=null && valueList.size()>0){
            StringBuilder fvalue = new StringBuilder();
            fvalue.append("( ");
            for(int i=0;i<valueList.size();i++){
                if(i>0){
                    fvalue.append(" OR ");
                }
                fvalue.append(valueList.get(i));
            }
            fvalue.append(" )");
            return fvalue.toString();
        }
        return "*";
    }

    /**
     * 获取多值查询条件值,过滤掉filtValue
     * @param valueArray
     * @return
     */
    public static String getConditionValueAndFiltValue(String[] valueArray,String filtValue){
        if(valueArray!=null && valueArray.length>0){
            List<String> list = new ArrayList<String>();
            for(int i=0;i<valueArray.length;i++){
               if(valueArray[i] == null || (filtValue !=null && filtValue.equals(valueArray[i]))){
                   continue;
               }else{
                   list.add(valueArray[i]);
               }
            }

            return getConditionValueForArrayValue(list);
        }
        return "*";
    }


}
